﻿using ServiceStack.Redis;
using ServiceStack.Redis.Generic;
using ServiceStack.Text;
using System;
using System.Collections.Generic;
using System.Linq;

namespace EventModel
{
    /// <summary>
    /// Redis操作类   
    /// </summary>
    public class RedisHelper
    {
        public static string readServer = "";
        public static string writeServer = "";
        #region -- 连接信息 --
        private static PooledRedisClientManager prcm = null;
        public RedisHelper()
        {
            CreateManager();
        }

        /// <summary>
        /// 创建链接池管理对象
        /// 支持读写分离，负载均衡，如果不实现读写分离，读和写的服务器配置成同一个即可
        /// </summary>
        private void CreateManager()
        {
            string[] writeServerList = SplitString(writeServer, ",");
            string[] readServerList = SplitString(readServer, ", ");

            prcm = new PooledRedisClientManager(readServerList, writeServerList,
                             new RedisClientManagerConfig
                             {
                                 MaxWritePoolSize = 60,
                                 MaxReadPoolSize = 60,
                                 AutoStart = true,
                             });
        }
        #endregion

        #region -- 内部私有方法 --

        private IList<T> ConllectionGetAll<T>(IRedisTypedClient<T> t)
        {
            return t.GetAll();
        }

        private IDictionary<string, T> ConllectionGetAll<T>(IRedisClient redis, IEnumerable<string> keys)
        {
            return redis.GetAll<T>(keys);
        }
        private static string[] SplitString(string strSource, string split)
        {
            return strSource.Split(split.ToArray());
        }
        #endregion

        #region -- 公用 --

        /// <summary>
        /// 清空数据库
        /// </summary>
        public void ClearAllDb()
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    redis.FlushAll();
                }
            }
            catch (Exception ex)
            {

            }

        }

        /// <summary> 
        /// 设置缓存过期 
        /// </summary> 
        /// <param name="key">key字符串</param> 
        /// <param name="datetime">缓存时间</param> 
        /// <returns>成功返回true，失败或key不存在返回false</returns>
        public bool SetExpire(string key, DateTime datetime)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    return redis.ExpireEntryAt(key, datetime);
                }
            }
            catch (Exception ex)
            {

                return false;
            }

        }

        #endregion

        #region -- Item --

        /// <summary>
        /// 存储对象,没有添加，有则覆盖
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="key">key字符串</param>
        /// <param name="t">存储对象(也可以是基本数据类型),保存为json格式</param>
        /// <returns>成功返回true,失败返回false</returns>
        public bool Item_Set<T>(string key, T t)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    return redis.Set(key, t, DateTime.MaxValue);
                }
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 设置缓存过期时间
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="t"></param>
        /// <param name="timeSpan"></param>
        /// <returns></returns>
        public bool Set<T>(string key, T t, TimeSpan timeSpan)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    return redis.Set<T>(key, t, timeSpan);
                }
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 设置缓存过期时间
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="t"></param>
        /// <param name="expressDateTimet"></param>
        /// <returns></returns>
        public bool Item_Set<T>(string key, T t, DateTime expressDateTimet)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    return redis.Set(key, t, expressDateTimet);
                }
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 获取对象,没有添加，有则覆盖
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="key">key字符串</param>
        /// <returns>返回对应的泛型类型的数据或对象</returns>
        public T Item_Get<T>(string key)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    return redis.Get<T>(key);
                }
            }
            catch (Exception ex)
            {
                return default(T);
            }

        }

        /// <summary>
        /// 移除对象
        /// </summary>
        /// <param name="key">key字符串</param>
        /// <returns>成功返回true，失败或key不存在 返回false</returns>
        public bool Item_Remove(string key)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    return redis.Remove(key);
                }
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        #endregion

        #region -- List --

        /// <summary>
        /// 获取集合中索引位置对应的元素
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="key">集合名称</param>
        /// <param name="index"></param>
        /// <returns>获取对应索引位置的元素</returns>
        public T List_GetTByIndex<T>(string key, int index)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    var redisTypedClient = redis.As<T>();
                    return redisTypedClient.Lists[key][index];
                }
            }
            catch (Exception ex)
            {
                return default(T);
            }
        }

        /// <summary>
        /// 获取集合中的所有元素 List &lt; T &gt;
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="key">集合名称</param>
        /// <returns>获取集合中的所有元素</returns>
        public List<T> List_GetAll<T>(string key)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    var redisTypedClient = redis.As<T>();
                    return redisTypedClient.Lists[key].GetAll();
                }
            }
            catch (Exception ex)
            {
                return default(List<T>);
            }
        }

        /// <summary>
        /// 获取集合中的所有元素
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="key">集合名称</param>
        /// <returns>获取集合中的所有元素</returns>
        public List<T> ListGetAll<T>(string key)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    var redisTypedClient = redis.As<T>();
                    return redisTypedClient.Lists[key].GetAll();
                }
            }
            catch (Exception ex)
            {
                return default(List<T>);
            }
        }

        /// <summary>
        /// 向集合中添加元素(也可以是基本数据类型)
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="key">集合的名称(key)</param>
        /// <param name="t">添加的对象</param>
        public void List_Add<T>(string key, T t)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    var redisTypedClient = redis.As<T>();
                    redisTypedClient.AddItemToList(redisTypedClient.Lists[key], t);
                }
            }
            catch (Exception ex)
            {

            }
        }

        /// <summary>
        /// 从集合中移除元素指定元素
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="key">集合的名称</param>
        /// <param name="t">需要移除的元素</param>
        /// <returns>成功返回ture，失败返回false</returns>
        public bool List_Remove<T>(string key, T t)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    var redisTypedClient = redis.As<T>();

                    return redisTypedClient.RemoveItemFromList(redisTypedClient.Lists[key], t) > 0;
                }
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 从集合中移除所有元素
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="key">集合的名称</param>
        public void List_RemoveAll<T>(string key)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    var redisTypedClient = redis.As<T>();
                    redisTypedClient.Lists[key].RemoveAll();
                }
            }
            catch (Exception ex)
            {

            }
        }

        /// <summary>
        /// 集合中元素的个数
        /// </summary>
        /// <param name="key">集合名称</param>
        /// <returns>返回集合的个数</returns>
        public long List_Count(string key)
        {
            try
            {
                using (IRedisClient redis = prcm.GetReadOnlyClient())
                {
                    return redis.GetListCount(key);
                }
            }
            catch (Exception ex)
            {
                return 0;
            }
        }

        /// <summary>
        /// 获取范围内的集合数据
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="key">集合名称</param>
        /// <param name="start">开始位置Index索引</param>
        /// <param name="count">结束位置Index索引</param>
        /// <returns>返回元素集合List，包含开始以及结束位置</returns>
        public List<T> List_GetRange<T>(string key, int start, int count)
        {
            try
            {
                using (IRedisClient redis = prcm.GetReadOnlyClient())
                {
                    var redisTypedClient = redis.As<T>();
                    return redisTypedClient.Lists[key].GetRange(start, start + count - 1);
                }
            }
            catch (Exception ex)
            {
                return default(List<T>);
            }
        }

        /// <summary>
        /// 获取集合数据
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="key">集合名称</param>
        /// <returns>返回集合内的所有元素List</returns>
        public List<T> List_GetList<T>(string key)
        {
            try
            {
                using (IRedisClient redis = prcm.GetReadOnlyClient())
                {
                    var redisTypedClient = redis.As<T>();
                    return redisTypedClient.Lists[key].GetRange(0, redisTypedClient.Lists[key].Count);
                }
            }
            catch (Exception ex)
            {
                return default(List<T>);
            }
        }

        /// <summary>
        /// 模拟按页返回对应部分元素
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="key">集合名称</param>
        /// <param name="pageIndex">所需要的页索引</param>
        /// <param name="pageSize">每页记录数</param>
        /// <returns>返回获取到的页的所有元素</returns>
        public List<T> List_GetList<T>(string key, int pageIndex, int pageSize)
        {
            try
            {
                int start = pageSize * (pageIndex - 1);
                return List_GetRange<T>(key, start, pageSize);
            }
            catch (Exception ex)
            {
                return default(List<T>);
            }
        }

        #endregion

        #region -- Set --

        /// <summary>
        /// 获取集合中的所有元素HashSet&lt; T &gt;
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="key">集合名称</param>
        /// <returns>获取集合中的所有元素</returns>
        public HashSet<T> Set_GetAll<T>(string key)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                var redisTypedClient = redis.As<T>();
                return redisTypedClient.Sets[key].GetAll();
            }
        }

        /// <summary>
        /// 向Set集合添加元素，不会重复添加
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="key">集合名称</param>
        /// <param name="t">添加的元素</param>
        public void Set_Add<T>(string key, T t)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                var redisTypedClient = redis.As<T>();
                redisTypedClient.Sets[key].Add(t);
            }
        }

        /// <summary>
        /// 判断Set集合是否包含当前元素
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="key">集合名称</param>
        /// <param name="t">需要判断的元素</param>
        /// <returns>包含返回true，不包含或key不存在 返回false</returns>
        public bool Set_Contains<T>(string key, T t)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                var redisTypedClient = redis.As<T>();
                return redisTypedClient.Sets[key].Contains(t);
            }
        }

        /// <summary>
        /// 移除Set集合中对应的元素
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="key">集合名称</param>
        /// <param name="t">需要移除的元素</param>
        /// <returns>成功或key不存在或者元素不存在都返回true</returns>
        public bool Set_Remove<T>(string key, T t)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    var redisTypedClient = redis.As<T>();
                    return redisTypedClient.Sets[key].Remove(t);
                }
            }
            catch (Exception ex)
            {
                return false;
            }

        }

        #endregion

        #region -- Hash --

        /// <summary>
        /// 判断hash中某个对象是否存在
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="key">hash名称 key字符串</param>
        /// <param name="dataKey">对象的key名称</param>
        /// <returns>存在返回true，不存在返回false</returns>
        public bool Hash_Exist(string key, string dataKey)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                return redis.HashContainsEntry(key, dataKey);
            }
        }
        /// <summary> 
        /// 判断某个数据是否已经被缓存 
        /// </summary> 
        /// <typeparam name="T"></typeparam> 
        /// <param name="key"></param> 
        /// <param name="dataKey"></param> 
        /// <returns></returns> 
        public static bool Hash_Exist<T>(string key, string dataKey)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                return redis.HashContainsEntry(key, dataKey);
            }
        }

        /// <summary>
        /// 存储数据到hash表
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="key">hash集合的key 名称</param>
        /// <param name="dataKey">对象的key名称</param>
        /// <param name="t">存储的对象</param>
        /// <returns>成功返回true,保存json字符串</returns>
        public static bool Hash_Set<T>(string key, string dataKey, T t)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                string value = JsonSerializer.SerializeToString(t);
                return redis.SetEntryInHash(key, dataKey, value);
            }
        }

        /// <summary> 
        /// 设置缓存过期 
        /// </summary> 
        /// <param name="key"></param> 
        /// <param name="datetime"></param> 
        public static void Hash_SetExpire(string key, DateTime datetime)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                redis.ExpireEntryAt(key, datetime);
            }
        }

        /// <summary>
        /// 移除hash中的某值 
        /// </summary>
        /// <param name="key">hash集合的key 名称</param>
        /// <param name="dataKey">对象的key名称</param>
        /// <returns>成功返回true，失败返回false</returns>
        public static bool Hash_Remove(string key, string dataKey)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                return redis.RemoveEntryFromHash(key, dataKey);
            }
        }

        /// <summary>
        /// 移除整个hash 
        /// </summary>
        /// <param name="key">hash集合的key 名称</param>
        /// <returns>成功返回true，失败返回false</returns>
        public static bool Hash_Remove(string key)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                return redis.Remove(key);
            }
        }

        /// <summary>
        /// 从hash集合中获取单个对象 
        /// </summary>
        /// <typeparam name="T">获取对象的类型</typeparam>
        /// <param name="key">hash集合的key 名称</param>
        /// <param name="dataKey">对象的key名称</param>
        /// <returns>返回对象</returns>
        public static T Hash_Get<T>(string key, string dataKey)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                string value = redis.GetValueFromHash(key, dataKey);
                return JsonSerializer.DeserializeFromString<T>(value);
            }
        }

        /// <summary>
        /// 获取整个hash集合的数据 
        /// </summary>
        /// <typeparam name="T">获取对象的类型</typeparam>
        /// <param name="key">hash集合的key 名称</param>
        /// <returns>返回对象集合</returns>
        public List<T> Hash_GetAll<T>(string key)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                var list = redis.GetHashValues(key);
                if (list != null && list.Count > 0)
                {
                    List<T> result = new List<T>();
                    foreach (var item in list)
                    {
                        var value = JsonSerializer.DeserializeFromString<T>(item);
                        result.Add(value);
                    }
                    return result;
                }
                return null;
            }
        }

        /// <summary>
        /// 获取Hash集合数量 
        /// </summary>
        /// <param name="key">hash集合的key 名称</param>
        /// <returns>返回集合元素的个数 long类型</returns>
        public static long Hash_GetCount(string key)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                return redis.GetHashCount(key);
            }
        }

        #endregion

        #region -- SortedSet --

        /// <summary>
        /// 添加对象到 SortedSet 
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="key">SortedSet的Key</param>
        /// <param name="t">添加的对象</param>
        /// <param name="score">对象的分数(score)可以设置为null</param>
        /// <returns>成功返回true，失败或对象存在返回false</returns>
        public bool SortedSet_Add<T>(string key, T t, double? score = null)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                string value = JsonSerializer.SerializeToString(t);
                if (score == null)
                {
                    return redis.AddItemToSortedSet(key, value);
                }
                return redis.AddItemToSortedSet(key, value, Convert.ToDouble(score));
            }
        }

        /// <summary>
        /// 移除数据从SortedSet 
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="key">SortedSet的key</param>
        /// <param name="t">移除的对象</param>
        /// <returns>成功返回true，失败或对象存在返回false</returns>
        public bool SortedSet_Remove<T>(string key, T t)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                string value = JsonSerializer.SerializeToString(t);
                return redis.RemoveItemFromSortedSet(key, value);
            }
        }

        /// <summary>
        /// 移除指定SortedSet范围内的对象
        /// </summary>
        /// <param name="key">SortedSet的key</param>
        /// <param name="minSize">范围的最小值Index 默认为0</param>
        /// <param name="maxsize">范围的最大值Index 默认为9999999</param>
        /// <returns>返回移除的元素的数量</returns>
        public long SortedSet_Trim(string key, int minSize = 0, int maxsize = 9999999)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                return redis.RemoveRangeFromSortedSet(key, minSize, maxsize);
            }
        }

        /// <summary>
        /// 获取SortedSet的长度 
        /// </summary>
        /// <param name="key">SortedSet的key</param>
        /// <returns>返回SortedSet的长度 </returns>
        public long SortedSet_Count(string key)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                return redis.GetSortedSetCount(key);
            }
        }

        /// <summary>
        /// 获取SortedSet的分页数据 
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="key">SortedSet的key</param>
        /// <param name="pageIndex">获取的页索引</param>
        /// <param name="pageSize">每页记录数</param>
        /// <returns>返回指定页的对象集合</returns>
        public List<T> SortedSet_GetList<T>(string key, int pageIndex, int pageSize)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                var list = redis.GetRangeFromSortedSet(key, (pageIndex - 1) * pageSize, pageIndex * pageSize - 1);
                if (list != null && list.Count > 0)
                {
                    List<T> result = new List<T>();
                    foreach (var item in list)
                    {
                        var data = JsonSerializer.DeserializeFromString<T>(item);
                        result.Add(data);
                    }
                    return result;
                }
            }
            return null;
        }

        /// <summary>
        /// 获取SortedSet的全部数据 
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="key">SortedSet的key</param>
        /// <returns>返回SortedSet的全部数据 </returns>
        public List<T> SortedSet_GetListALL<T>(string key)
        {
            using (IRedisClient redis = prcm.GetReadOnlyClient())
            {
                var list = redis.GetRangeFromSortedSet(key, 0, 9999999);
                if (list != null && list.Count > 0)
                {
                    List<T> result = new List<T>();
                    foreach (var item in list)
                    {
                        var data = JsonSerializer.DeserializeFromString<T>(item);
                        result.Add(data);
                    }
                    return result;
                }
            }
            return null;
        }
        #endregion

        #region -- Queue --
        /// <summary>
        /// 入队
        /// </summary>
        /// <param name="listid"></param>
        /// <param name="value"></param>
        public bool Enqueue(string listid, string value)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    redis.EnqueueItemOnList(listid, value);
                    return true;
                }
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        /// <summary>
        /// 出队
        /// </summary>
        /// <param name="listid"></param>
        /// <returns></returns>
        public string Dequeue(string listid)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    return redis.BlockingDequeueItemFromList(listid, null);
                }
            }
            catch (Exception ex)
            {
                return null;
            }
        }
        /// <summary>
        /// 队列中消息数量
        /// </summary>
        /// <param name="listid"></param>
        /// <returns></returns>
        public long GetQueueCount(string listid)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                return redis.GetListCount(listid);
            }
        }
        #endregion

        /// <summary>
        /// push订阅
        /// </summary>
        /// <param name="listid"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool PublishMessage(string listid, string value)
        {
            using (IRedisClient redis = prcm.GetClient())
            {
                redis.PublishMessage(listid, value);
                return true;
            }
        }

        /// <summary>
        /// Redis计数器，原子操作
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public long IncrNext(string key)
        {
            try
            {
                using (IRedisClient redis = prcm.GetClient())
                {
                    return redis.IncrementValue(key);
                }
            }
            catch (Exception ex)
            {
                return 0;
            }
        }
    }
}